package com.lry.basic.jvm.asm.transform_class.demo13;

import aj.org.objectweb.asm.*;

import static jdk.internal.org.objectweb.asm.Opcodes.*;

/**
 * 给方法计时
 */

public class MethodEmptyBodyVisitor extends ClassVisitor {

    private String methodName;
    private String methodDesc;
    public MethodEmptyBodyVisitor(int api, ClassVisitor cv,String methodName,String methodDesc) {
        super(api,cv);
        this.methodName = methodName;
        this.methodDesc = methodDesc;
    }


    @Override
    public MethodVisitor visitMethod(int access, String name, String desc, String sig, String[] exceptions) {
        MethodVisitor mv = super.visitMethod(access, name, desc, sig, exceptions);
        if(mv!=null&& methodName.equals(name)&&methodDesc.equals(desc)){
            boolean isAbstract = (access&Opcodes.ACC_ABSTRACT)==Opcodes.ACC_ABSTRACT;
            boolean isNative = (access&Opcodes.ACC_NATIVE)== Opcodes.ACC_NATIVE;
            if(!isAbstract&&!isNative){
                generateNewBody(mv,access,methodName,methodDesc);
                return null;
            }
        }
        return mv;
    }


    protected void generateNewBody(MethodVisitor mv, int methodAccess, String methodName, String methodDesc) {
        // (1) method argument types and return type
        Type t = Type.getType(methodDesc);
        Type[] argumentTypes = t.getArgumentTypes();
        Type returnType = t.getReturnType();


        // (2) compute the size of local variable and operand stack
        boolean isStaticMethod = ((methodAccess & Opcodes.ACC_STATIC) != 0);
        int localSize = isStaticMethod ? 0 : 1;
        for (Type argType : argumentTypes) {
            localSize += argType.getSize();
        }
        int stackSize = returnType.getSize();


        // (3) method body
        mv.visitCode();
        if (returnType.getSort() == Type.VOID) {
            mv.visitInsn(RETURN);
        }
        else if (returnType.getSort() >= Type.BOOLEAN && returnType.getSort() <= Type.DOUBLE) {
            mv.visitInsn(returnType.getOpcode(ICONST_1));
            mv.visitInsn(returnType.getOpcode(IRETURN));
        }
        else {
            mv.visitInsn(ACONST_NULL);
            mv.visitInsn(ARETURN);
        }
        //无需自己计算
//        mv.visitMaxs(stackSize, localSize);
        mv.visitMaxs(0, 0);
        mv.visitEnd();
    }
}
